﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;

namespace XCI.Helper
{
    /// <summary>
    /// Json序列化操作类
    /// </summary>
    public static class JsonHelper
    {
        /// <summary>
        /// 反序列化Json文件
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="filePath">文件路径</param>
        /// <param name="defaultValue">对象为空时的默认值</param>
        /// <param name="settings">序列化配置</param>
        public static T FromJsonFile<T>(string filePath, T defaultValue = default, JsonSerializerSettings settings = null) where T : class, new()
        {
            if (!File.Exists(filePath)) return defaultValue;
            
            var json = File.ReadAllText(filePath, System.Text.Encoding.UTF8);
            return FromJsonString(json, defaultValue, settings);
        }

        /// <summary>
        /// 反序列化Json字符串
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="json">json字符串</param>
        /// <param name="defaultValue">对象为空时的默认值</param>
        /// <param name="settings">序列化配置</param>
        public static T FromJsonString<T>(string json, T defaultValue = default(T), JsonSerializerSettings settings = null)
        {
            settings = settings ?? GetDefaultSetting();
            var data = default(T);
            if (!string.IsNullOrWhiteSpace(json))
            {
                data = JsonConvert.DeserializeObject<T>(json, settings);
            }
            if (data != null)
            {
                return data;
            }

            return defaultValue;
        }

        /// <summary>
        /// 序列化为Json字符串并保存到文件
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="data">数据对象</param>
        /// <param name="settings">序列化配置</param>
        public static void ToJsonFile(string filePath, object data, JsonSerializerSettings settings = null)
        {
            var json = ToJsonString(data,settings);
            IOHelper.CreateDirectoryByPath(filePath);
            File.WriteAllText(filePath, json, System.Text.Encoding.UTF8);
        }

        /// <summary>
        /// 序列化为Json字符串
        /// </summary>
        /// <param name="data">数据对象</param>
        /// <param name="settings">序列化配置</param>
        public static string ToJsonString(object data, JsonSerializerSettings settings = null)
        {
            if (data == null) return string.Empty;
            settings = settings ?? GetDefaultSetting();
            return JsonConvert.SerializeObject(data, settings);
        }

        /// <summary>
        /// 获取默认Json序列化默认设置
        /// </summary>
        /// <param name="formatting">Json是否格式化</param>
        public static JsonSerializerSettings GetDefaultSetting(Formatting formatting = Formatting.Indented)
        {
            var settings = new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                ReferenceLoopHandling = ReferenceLoopHandling.Error,
                NullValueHandling = NullValueHandling.Include,
                DateFormatString = "yyyy-MM-dd HH:mm:ss",
                Formatting = formatting
            };
            settings.Converters.Add(new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy() });
            return settings;
        }

        /// <summary>
        /// Json对象转换
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="obj">待转换的对象</param>
        /// <returns>返回转换后的对象</returns>
        public static T ToObject<T>(object obj)
        {
            switch (obj)
            {
                case T value1:
                    return value1;
                case JContainer value2:
                    return value2.ToObject<T>();
                default:
                    return default(T);
            }
        }
    }
}